package smn.dao.managerimpl;

import org.springframework.orm.jpa.support.JpaDaoSupport;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.orm.jpa.JpaCallback;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceException;
import javax.persistence.Query;
import java.util.Collection;
import java.util.List;

/**
 * User: Abdulaziz
 * Date: 1/8/12
 * Time: 10:19 AM
 */
@Transactional(propagation = Propagation.SUPPORTS)
public abstract class AbstractJpaDaoSupport<T> extends JpaDaoSupport {
    protected abstract Class<T> getObjectClass();
    protected abstract EntityManagerFactory getEntityManagerFactory();
    protected EntityManager getEm() {
        return getEntityManagerFactory().createEntityManager();
    }

    protected String getClassName() {
        return getObjectClass().getName();
    }

    public T findById(long id) {
        return getJpaTemplate().find(getObjectClass(), id);
    }

    public T findById(int id) {
        return getJpaTemplate().find(getObjectClass(), id);
    }


    public List<T> findAll() {
        return getJpaTemplate().find("from " + getClassName());
    }

    public List<T> findAll(boolean isAcs) {
        if(isAcs)
            return getJpaTemplate().find("from " + getClassName()+" t order by t.id asc ");
        else
            return getJpaTemplate().find("from " + getClassName()+" t order by t.id desc ");
    }


    @Transactional(propagation = Propagation.REQUIRED)
    public T update(T t) {
        getJpaTemplate().persist(t);
        return t;
    }


    @Transactional(propagation = Propagation.REQUIRED)
    public void update(Collection<T> list) {
        for (T entity : list)
            getJpaTemplate().persist(entity);
    }


    @Transactional(propagation = Propagation.REQUIRED)
    public void delete(Collection<T> list) {
        for (T entity : list)
            getJpaTemplate().remove(entity);
    }


    @Transactional(propagation = Propagation.REQUIRED)
    public T delete(T t) {
        getJpaTemplate().remove(t);
        return t;
    }

    public int count() {
        return getJpaTemplate().getEntityManager().createQuery("SELECT count(*) FROM " + getClassName()).getMaxResults();
    }


    @Transactional(propagation = Propagation.REQUIRED)
    public T merge(T t) {
        getJpaTemplate().merge(t);
        return t;
    }


    @Transactional(propagation = Propagation.REQUIRED)
    public void merge(Collection<T> list) {
        for (T entity : list)
            getJpaTemplate().merge(entity);

    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void persist(Collection<T> list) {
        for (T entity : list)
            getJpaTemplate().persist(entity);

    }


    @Transactional(propagation = Propagation.REQUIRED)
    public T persist(T t) {
        getJpaTemplate().persist(t);
        return t;
    }

    public List<T> list(final String query, final int startIndex, final int maxResult) {
        List<T> res = getJpaTemplate().execute(new JpaCallback<List<T>>() {
            public List<T> doInJpa(EntityManager em) throws PersistenceException {
                Query q = em.createQuery(query);
                q.setFirstResult(startIndex);
                q.setMaxResults(maxResult);
                return q.getResultList();
            }
        });
        return res;
    }

    public List<T> list(final String query) {
        List<T> res = getJpaTemplate().execute(new JpaCallback<List<T>>() {
            public List<T> doInJpa(EntityManager em) throws PersistenceException {
                Query q = em.createQuery(query);
                return q.getResultList();
            }
        });
        return res;
    }

    public T getSingleResult(final String query){
        T res = getJpaTemplate().execute(new JpaCallback<T>() {
			public T doInJpa(EntityManager em) throws PersistenceException {
				Query q = em.createQuery(query);
				return (T)q.getSingleResult();
			}
		});
		return res;
    }


}
